﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rotempco.BaseClass.Objects.ResultObjects;
using Rotempco.BaseClass.Objects.Enums;
using Rotempco.BaseClass.Objects.EntityObjects;
using Rotempco.BaseClass.Objects.ReturnObjects;
using Rotempco.BaseClass.Objects.AttributeStoreObjects;

namespace Rotempco.BaseClass.Logic
{
    public class LoginLogic
    {
        internal static LoginResult Login(string email, string passwordHash)
        {
            if (!EmailLogic.IsValidEmail(email))
                return CreateLoginResult(LoginResultEnum.InvalidEmail, loginUserName: email);

            if (string.IsNullOrWhiteSpace(passwordHash))
                return CreateLoginResult(LoginResultEnum.InvalidPassword, loginUserName: email);

            PasswordSetting passwordSettings = Factory.PasswordSetting.GetPasswordSettings();

            LoginUser loginUser = Factory.LoginUser.GetSingle(email: email);
            if (loginUser == null)
                return CreateLoginResult(LoginResultEnum.LoginUserNotFound, loginUserName: email);

            List<LoginHistory> loginHistoryList = Factory.LoginHistory.GetList(loginUserId: loginUser.LoginUserId, getLastEntries: passwordSettings.NumberOfFailedLoginRequests).OrderByDescending(l => l.LoginHistoryId).ToList();
            LoginHistory lastLogin = loginHistoryList.FirstOrDefault();

            // Check if account must change password
            if (passwordSettings.PasswordExpirationDays.HasValue && passwordSettings.PasswordExpirationDays > 0)
            {
                PasswordHistory passwordHistory = Factory.PasswordHistory.GetList(getLastEntries: 1, loginUserId: loginUser.LoginUserId).FirstOrDefault();
                if (passwordHistory != null)
                {
                    TimeSpan passwordAge = DateTime.Now - passwordHistory.CreatedDate;
                    if (passwordAge.Days >= passwordSettings.PasswordExpirationDays.Value)
                        return CreateLoginResult(LoginResultEnum.ChangePassword, email, loginUser);
                }
            }

            // Check if account is suspended:
            if (lastLogin != null && lastLogin.SuspendedUntil.HasValue && lastLogin.SuspendedUntil.Value > DateTime.Now)
                return CreateLoginResult(LoginResultEnum.AccountSuspended, loginUserName: email, loginUser: loginUser, accountSuspendedUntil: lastLogin.SuspendedUntil.Value);

            // If wrong password and the last <NumberOfFailedLoginRequests> login attempts where false and account not suspended => Suspend account.
            if (passwordHash != loginUser.PasswordHash)
            {
                if (lastLogin != null
                    && loginHistoryList.Count >= passwordSettings.NumberOfFailedLoginRequests
                    && (from f in loginHistoryList where f.Success == false && f.SuspendedUntil == null select f).Count() == passwordSettings.NumberOfFailedLoginRequests
                    )
                    return CreateLoginResult(LoginResultEnum.AccountSuspended, loginUserName: email, loginUser: loginUser, accountSuspendedUntil: DateTime.Now +  TimeSpan.FromMinutes(passwordSettings.PauseMinutesAfterNumberOfFailedLogins.Value));
                else
                    return CreateLoginResult(LoginResultEnum.InvalidPassword, loginUserName: email, loginUser: loginUser);
            }

            return CreateLoginResult(LoginResultEnum.Success, loginUserName: email, loginUser: loginUser);
        }




        private static LoginResult CreateLoginResult(LoginResultEnum loginResultEnum, string loginUserName, LoginUser loginUser = null, DateTime? accountSuspendedUntil = null)
        {
            long? loginUserId = null;
            if (loginUser != null)
                loginUserId = loginUser.LoginUserId;

            bool success = (loginResultEnum == LoginResultEnum.Success ? true : false);

            LoginHistory loginHistory = new LoginHistory()
            {
                LoginName = loginUserName,
                LoginUserId = loginUserId,
                Success = success,
                Timestamp = DateTime.Now,
                SuspendedUntil = accountSuspendedUntil
            };
            Factory.LoginHistory.WriteToDB(loginHistory);

            return new LoginResult(loginResultEnum, loginUser: loginUser, accountSuspendedUntil: accountSuspendedUntil);
        }

        //internal static void SetStores(LoginUser loginUser)
        //{
        //    LoginStore.Instance.LoginUser = loginUser;
        //}
    }
}
